﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;

namespace sharpCmd.Classes
{
    /// <summary>
    /// Manages icons
    /// </summary>
    class IconManager
    {
        [DllImport("shell32.dll")]
        private static extern IntPtr SHGetFileInfo(
            string pszPath,
            uint dwFileAttributes,
            ref SHFILEINFO psfi,
            uint cbFileInfo,
            uint uFlags
        );

        [StructLayout(LayoutKind.Sequential)]
        private struct SHFILEINFO
        {
            private const int DISPLAY_NAME_MAX = 256;
            public const int NAMESIZE = 80;
            public IntPtr hIcon;
            public int iIcon;
            public uint dwAttributes;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DISPLAY_NAME_MAX)]
            public string szDisplayName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NAMESIZE)]
            public string szTypeName;
        };

        [DllImport("User32.dll")]
        private static extern int DestroyIcon(IntPtr hIcon);
       
        public enum IconSize
        {
            /// <summary>
            /// Large icon 32x32
            /// </summary>
            Large = 0,
            /// <summary>
            /// Small icon 16x16
            /// </summary>
            Small = 1
        }

        private const uint SHGFI_ICON = 0x000000100;
        private const uint SHGFI_DISPLAYNAME = 0x000000200;
        private const uint SHGFI_TYPENAME = 0x000000400;
        private const uint SHGFI_ATTRIBUTES = 0x000000800;
        private const uint SHGFI_ICONLOCATION = 0x000001000;
        private const uint SHGFI_EXETYPE = 0x000002000;
        private const uint SHGFI_SYSICONINDEX = 0x000004000;
        private const uint SHGFI_LINKOVERLAY = 0x000008000;
        private const uint SHGFI_SELECTED = 0x000010000;
        private const uint SHGFI_ATTR_SPECIFIED = 0x000020000;
        private const uint SHGFI_LARGEICON = 0x000000000;
        private const uint SHGFI_SMALLICON = 0x000000001;
        private const uint SHGFI_OPENICON = 0x000000002;
        private const uint SHGFI_SHELLICONSIZE = 0x000000004;
        private const uint SHGFI_PIDL = 0x000000008;
        private const uint SHGFI_USEFILEATTRIBUTES = 0x000000010;
        private const uint SHGFI_ADDOVERLAYS = 0x000000020;
        private const uint SHGFI_OVERLAYINDEX = 0x000000040;

        private const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
        private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;


        //TODO refactor GetFileIcon and GetDirectoryIcon to share code
        /// <summary>
        /// Get Icon for a file
        /// </summary>
        /// <param name="name">full name or extension (!) INCLUDING dot (.txt)</param>
        /// <param name="size"></param>
        /// <param name="linkOverlay"></param>
        /// <returns></returns>
        public static Icon GetFileIcon(string filename, IconSize size, bool overlay)
        {
            SHFILEINFO info = new SHFILEINFO();
            uint flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES;
            if (overlay)
                flags += SHGFI_ADDOVERLAYS;
            flags += size == IconSize.Small ? SHGFI_SMALLICON : SHGFI_LARGEICON;
            flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES | SHGFI_SMALLICON | SHGFI_ADDOVERLAYS;
            SHGetFileInfo(filename,
                FILE_ATTRIBUTE_NORMAL,
                ref info,
                (uint)Marshal.SizeOf(info),
                flags);
            //copy and delete icon
            Icon icon = (Icon)Icon.FromHandle(info.hIcon).Clone();
            DestroyIcon(info.hIcon);
            return icon;
        }

        /// <summary>
        /// Get icon for a directory
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="size"></param>
        /// <param name="overlay"></param>
        /// <returns></returns>
        public static Icon GetDirectoryIcon(string filename, IconSize size, bool overlay)
        {
            SHFILEINFO info = new SHFILEINFO();
            uint flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES;
            if (overlay)
                flags += SHGFI_ADDOVERLAYS;
            flags += size == IconSize.Small ? SHGFI_SMALLICON : SHGFI_LARGEICON;
            flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES | SHGFI_SMALLICON | SHGFI_ADDOVERLAYS;
            SHGetFileInfo(filename,
                FILE_ATTRIBUTE_DIRECTORY,
                ref info,
                (uint)Marshal.SizeOf(info),
                flags);
            //copy and delete icon
            Icon icon = (Icon)Icon.FromHandle(info.hIcon).Clone();
            DestroyIcon(info.hIcon);
            return icon;
        }
    }
}
